using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using DataAccess;
using MongoDB;

namespace SkynetMongoDBAccess;

public class MongoEntityDB<T> : MongoAbstractDB, IMongoAccess<T> where T : class
{
	private MongoCollection<T> _mongoCollection;

	private MongoCollection<T> GetMongoCollcetion
	{
		get
		{
			if (_mongoCollection == null)
			{
				_mongoCollection = base.GetDataBase.GetCollection<T>(base.CollectionName) as MongoCollection<T>;
			}
			return _mongoCollection;
		}
	}

	public IQueryable<T> Query => GetMongoCollcetion.Linq();

	public MongoEntityDB(string conString, string collectionName)
		: base(conString)
	{
		if (string.IsNullOrEmpty(collectionName))
		{
			base.CollectionName = typeof(T).Name;
		}
		else
		{
			base.CollectionName = collectionName;
		}
	}

	public MongoEntityDB(string connection, string collection, long cachelength)
		: base(connection, cachelength)
	{
		base.CollectionName = collection;
	}

	public void Insert(T document)
	{
		GetMongoCollcetion.Insert(document);
	}

	public void Insert(List<T> list)
	{
		GetMongoCollcetion.Insert(list);
	}

	public void Save(T document)
	{
		GetMongoCollcetion.Save(document, safemode: false);
	}

	public void Delete(Expression<Func<T, bool>> filter)
	{
		LinqExtensions.Remove(GetMongoCollcetion, filter);
	}

	public void Modify(T document, Expression<Func<T, bool>> filter)
	{
		LinqExtensions.Update(GetMongoCollcetion, document, filter);
	}

	public void ModifyAll(T document, Expression<Func<T, bool>> filter)
	{
		LinqExtensions.UpdateAll(GetMongoCollcetion, document, filter);
	}

	public void DeleteAll()
	{
		GetMongoCollcetion.Remove((T o) => true);
	}

	public List<T> FindAll()
	{
		return GetMongoCollcetion.FindAll().Documents.ToList();
	}

	public IEnumerable<T> Find(Expression<Func<T, bool>> filter)
	{
		return LinqExtensions.Find(GetMongoCollcetion, filter).Documents;
	}

	public IEnumerable<T> Find(Expression<Func<T, bool>> filter, int index, int count, out int maxCount)
	{
		IQueryable<T> source = GetMongoCollcetion.Linq();
		maxCount = source.Where(filter).Count();
		return source.Where(filter).Skip(index).Take(count)
			.ToList();
	}

	public void GroupBy(string groupName)
	{
		GetMongoCollcetion.MapReduce().Map(new Code("\r\n                    function() {\r\n                        emit(this." + groupName + ",1);\r\n                    }")).Reduce(new Code("\r\n                    function(key, values) {\r\n                        var sum = 0;\r\n                        values.forEach(function(prev) {\r\n                            sum += prev;\r\n                        });\r\n                        return sum;\r\n                    }"))
			.Out("MapReduce")
			.Documents.ToList();
	}

	public T FindOne(Expression<Func<T, bool>> filter)
	{
		return LinqExtensions.FindOne(GetMongoCollcetion, filter);
	}

	public void dispose()
	{
		Dispose();
	}
}
